import { _decorator, Component, Node, sp, Animation } from "cc"
import { ClientEvent } from "../framework/ClientEvent"
import ResManager from "../framework/ResManager"
import { Prefab } from "cc"
import { instantiate } from "cc"
import { ItemBase } from "./itemBase"
import { GlobalData } from "../GlobalData"
import { constant } from "../framework/constant"
import { util } from "../util/util"
import { Bullet } from "./Bullet"
import { Label } from "cc"
import { Vec3 } from "cc"
import { Tween } from "cc"
import { AudioManager } from "../framework/AudioManager"
import { GameItemHp } from "./GameItemHp"
import { UITransform } from "cc"
import { Sprite } from "cc"
const { ccclass, property } = _decorator

@ccclass("Player")
export class Player extends ItemBase {
  private nAttAckTarget: Node = null

  protected bulletId: number = 1

  protected attackBefore: number = 0

  public roleId: number = 0

  public isCompleteEffect: boolean = false

  public nodeHp: Node = null

  private animation: Animation = null

  private nodeAnimation: Node = null

  private curShieldHp: number = 0

  private maxShieldHp: number = 0

  onLoad() {
    this.nodeAnimation = this.node.getChildByName("animation")
    this.animation = this.node.getChildByName("animation").getComponent(Animation)
  }

  start() {
    this.playAnimation(constant.PLAYER_ANI_TYPE.IDLE)
    GlobalData.instance.arrNodePlayerRole.push(this.node)
    this.rScale = Math.abs(this.node.scaleX)
  }

  protected onEnable(): void {
    ClientEvent.on("onGDefenseChange", this.onGDefenseChange, this)
    ClientEvent.on("onGHealthRecoveryChange", this.onGHealthRecoveryChange, this)
    ClientEvent.on("onGameOver", this.onGameOver, this)
  }

  protected onDisable(): void {
    ClientEvent.off("onGDefenseChange", this.onGDefenseChange, this)
    ClientEvent.off("onGHealthRecoveryChange", this.onGHealthRecoveryChange, this)
    ClientEvent.off("onGameOver", this.onGameOver, this)
  }
  init(roleId: number) {
    this.isEnemy = false
    this.roleId = roleId
    const roleType = "role" + roleId
    const data = GlobalData.instance.roleData[roleType]

    this.sName = data.name
    this.maxHp = data.hp
    this.currHp = this.maxHp
    this.attackScope = data.attackScope
    this.currAttack = data.attack
    this.moveSpeed = 1 //data.moveSpeed
    this.attackBefore = data.attackBefore
    this.beAttackScope = data.beAttackScope
    this.attackSpeed = data.attackSpeed
    this.bulletId = this.roleId
    this.initNodeHp()
  }

  private initNodeHp() {
    const nodeHpParent = GlobalData.instance.nodeGame.getChildByName("hpParent")
    let prefab = ResManager.instance.getRes("prefabs/game/gameObject/nodeHp", Prefab)
    if (prefab) {
      this.nodeHp = instantiate(prefab)
      nodeHpParent.addChild(this.nodeHp)
      const gameHp: GameItemHp = this.nodeHp.getComponent(GameItemHp)
      gameHp.init(this.node, this.isEnemy)
    }
  }

  private numAttackBefore: number = 0
  private numAttackCd: number = 0
  /**回复技能 */
  private numRegenerate: number = 0

  update(deltaTime: number) {
    // return
    if (!this.node || !this.node.isValid || this.isDie) return
    if (!GlobalData.instance.getGameState()) {
      this.playAnimation(constant.PLAYER_ANI_TYPE.IDLE, true)
      return
    }
    if(!GlobalData.instance.numMonsterSlow) return


    if (this.nodeShield) {
      if (this.curShieldHp) {
        this.nodeShield.active = true
      } else {
        this.nodeShield.active = false
      }
    }

    if (this.isCompleteEffect || this.isTouching) return
    if (GlobalData.instance.gHealthRecovery > 1) {
      this.numRegenerate += deltaTime
      if (this.numRegenerate >= 2.0) {
        this.numRegenerate = 0
        this.healthRecovery()
      }
    }

    /**攻击前奏 */
    if (this.isAttackAction) {
      this.numAttackBefore += deltaTime
      if (this.numAttackBefore >= this.getAttackBefore()) {
        this.isAttackAction = false
        this.onAttackTarget(this.posAttack)
        this.posAttack = null
      }
    }

    /**攻击cd */
    if (this.isAttackCd) {
      this.numAttackCd += deltaTime
      if (this.numAttackCd >= this.getAttackSpeed()) {
        this.isAttackCd = false
        this.endAttackTarget()
      }
      return
    }

    this.nAttAckTarget = this.findTargetToAttack()
    if (this.nAttAckTarget) {
      let dis = util.getTwoPosXYLength(
        this.node.positionX,
        this.node.positionY,
        this.nAttAckTarget.positionX,
        this.nAttAckTarget.positionY
      )
      if (dis < this.getAttackScope()) {
        this.isAttackCd = true
        this.startAttAckTarget()
        return
      }
    }
    this.playAnimation(constant.PLAYER_ANI_TYPE.IDLE, true)
  }

  private isTouching: boolean = false
  onTouchStart() {
    this.isTouching = true
    this.playAnimation(constant.PLAYER_ANI_TYPE.IDLE, true)
  }

  onTouchEnd() {
    this.isTouching = false
  }

  findTargetToAttack(): Node {
    if (GlobalData.instance.arrNodeMonster.length > 0) {
      let disAttack: number = 0
      let nodeAttack: Node = null
      for (let i: number = 0; i < GlobalData.instance.arrNodeMonster.length; i++) {
        const node = GlobalData.instance.arrNodeMonster[i]
        const dis = util.getTwoPosXYLength(this.node.positionX, this.node.positionY, node.positionX, node.positionY)
        if (disAttack === 0 || disAttack > dis) {
          disAttack = dis
          nodeAttack = node
        }
      }
      return nodeAttack
    }
    return null
  }

  private animationName: string = ""
  protected callbackAnimate: (...args: any[]) => void
  /**
   * 播放玩家帧动画
   */
  public playAnimation(animationName: string, loop: boolean = true, callback?: (...args: any[]) => void) {
    if (this.animationName == animationName && loop) return
    this.animationName = animationName
    if (this.callbackAnimate) this.callbackAnimate = null
    if (this.animationName == "attack") {
      const clip = this.animation.getState("attack")
      clip.speed = 0.2 + (1 - GlobalData.instance.getCurrPlayerAttackSpeed()) * 0.5
      this.animation.play(animationName)
    } else {
      this.animation.play(animationName)
    }
    if (!loop) {
      if (callback) {
        this.callbackAnimate = callback
        this.animation.once(Animation.EventType.FINISHED, this.callbackAnimate, this)
      }
    }
  }

  private posAttack: Vec3 = null
  startAttAckTarget() {
    this.playAnimation(constant.PLAYER_ANI_TYPE.ATTACK, false, () => {
      this.playAnimation(constant.MONSTER_ANI_TYPE.IDLE, true)
    })
    this.posAttack = this.nAttAckTarget.getPosition()
    this.isAttackAction = true
    this.isAttackCd = true
    this.numAttackBefore = 0
    this.numAttackCd = 0
    // this.scheduleOnce(() => {
    //   this.onAttackTarget(pos)
    // }, this.attackBefore)
    // this.scheduleOnce(this.endAttackTarget, this.getAttackSpeed())
  }

  onAttackTarget(pos: Vec3) {
    AudioManager.instance.playEffect("sm_player_attack")
    const bulletId = this.bulletId
    const strBullet: string = `prefabs/game/bullet/bullet${bulletId}`
    ResManager.instance.loadRes(strBullet, Prefab, (error, prefab) => {
      if (prefab) {
        if (this.nAttAckTarget && this.nAttAckTarget.isValid) {
          pos = this.nAttAckTarget.getPosition()
        }
        const selfPos = this.node.getPosition()
        const angle = util.getTwoPosXYAngle(selfPos, pos)
        const distance = 50

        const func = (angle: number) => {
          let node = instantiate(prefab)
          let bullet: Bullet = node.addComponent(Bullet)
          if (bullet) {
            node.angle = angle
            const angleInRadians = angle * (Math.PI / 180) // 将角度转换为弧度
            const dx = Math.cos(angleInRadians) * distance // 计算 x 方向的移动
            const dy = Math.sin(angleInRadians) * distance // 计算 y 方向的移动
            node.setPosition(this.node.positionX + dx, this.node.positionY + dy)
            bullet.initTarget(bulletId, this.getCurrAttack(), this.isEnemy)
          }
          let bulletParent: Node = GlobalData.instance.nodeGame.getChildByName("bulletParent")
          bulletParent.addChild(node)
        }
        if (this.bulletId == 1 || this.bulletId == 5) {
          func(angle + 10)
          func(angle - 10)
        }
        func(angle)
      }
    })
  }

  endAttackTarget() {
    this.isAttackCd = false
    this.playAnimation(constant.PLAYER_ANI_TYPE.IDLE, true)
  }

  public getIsCanTouch() {
    return !this.isDie
  }

  public endCompleteEffect() {
    this.isCompleteEffect = false
  }

  public getAttackScope() {
    return this.node.positionX < -450 ? this.attackScope + 120 : this.attackScope
  }

  public getCurrAttack() {
    return this.currAttack
  }

  private getAttackSpeed() {
    let speed = this.attackSpeed * GlobalData.instance.getCurrPlayerAttackSpeed()
    return speed
  }

  private getAttackBefore() {
    return this.attackBefore * GlobalData.instance.getCurrPlayerAttackSpeed()
  }

  private isBeAttackAni: boolean = false
  onBeAttack(attack: number, nodeBeAttack?: Node): void {
    if (!this.isBeAttackAni) {
      this.isBeAttackAni = true
      const sprite = this.nodeAnimation.getComponent(Sprite)
      new Tween(sprite)
        .to(0.1, { colorG: 37, colorB: 37 })
        .delay(0.1)
        .to(0.1, { colorG: 255, colorB: 255 })
        .call(() => {
          this.isBeAttackAni = false
        })
        .start()
    }
    super.onBeAttack(attack, nodeBeAttack)
  }

  protected changeHp(value: number) {
    // return
    if (!GlobalData.instance.isGameStart || GlobalData.instance.isGameOver || GlobalData.instance.isGamePause) return
    value = Math.round(value)
    if (value > 0) {
      GlobalData.instance.arrRoleBeDamage[this.bulletId - 1] += value
    
    }

    if (this.curShieldHp > 0) {
      this.curShieldHp -= value
      if (this.curShieldHp < 0) {
        this.currHp += this.curShieldHp
        this.curShieldHp = 0
      }
    } else {
      if(GlobalData.instance.curLevel < 2 && this.currHp <= this.maxHp * 0.6 ){
        value *= 0.4
      }
      this.currHp -= value
    }

    this.onChangeHp(this.currHp)
  }

  protected onChangeHp(hp: number) {
    if (!this.maxHp) return
    this.currHp = hp
    if (this.currHp > this.maxHp) {
      this.currHp = this.maxHp
    }
    if (this.nodeHp) {
      const gameHp: GameItemHp = this.nodeHp.getComponent(GameItemHp)
      gameHp.updateItemHp(this.currHp, this.maxHp)
      gameHp.updateItemShieldHp(this.curShieldHp, this.maxShieldHp)
    }

    if (this.currHp <= 0) {
      this.currHp = 0
      this.isDie = true
    }
  }

  protected showDie(): void {
    ClientEvent.emit("onPlayerDie", this.node)
    new Tween(this.node).to(0.5, { alpha: 0 }).start()
    this.nodeHp.destroy()
    this.onDisable()
  }

  private nodeShield: Node = null
  //保护罩
  protected onGDefenseChange() {
    if (this.nodeShield) {
      this.nodeShield.active = true
    } else {
      ResManager.instance.loadRes("prefabs/game/buff/shield", Prefab, (err, prefab: Prefab) => {
        if (prefab) {
          if (this.nodeShield) {
            this.nodeShield.destroy()
          }
          this.nodeShield = instantiate(prefab)
          this.node.addChild(this.nodeShield)
          this.nodeShield.setPosition(new Vec3(0, 0))
        }
      })
    }

    this.maxShieldHp = Math.max(GlobalData.instance.gDefense * this.maxHp * 0.1,this.maxHp)
    this.curShieldHp = this.maxShieldHp
  }

  protected onGHealthRecoveryChange() {
    const recovery: number = 50
    this.maxHp += recovery
    this.onChangeHp(this.currHp + recovery)
  }

  protected onGameOver() {}

  private nodeRecovery: Node = null
  protected healthRecovery() {
    if (this.isDie) return
    ResManager.instance.loadRes("prefabs/game/buff/regeneration", Prefab, (err, prefab: Prefab) => {
      if (prefab) {
        this.nodeRecovery = instantiate(prefab)
        this.node.addChild(this.nodeRecovery)
        this.nodeRecovery.setPosition(new Vec3(0, 0))
        new Tween(this.nodeRecovery)
          .delay(1)
          .call(() => {
            this.nodeRecovery.destroy()
          })
          .start()
      }
    })

    if (this.currHp < this.maxHp) {
      const recovery = (GlobalData.instance.gHealthRecovery - 1) * 20
      this.onChangeHp(this.currHp + recovery)
    }
  }

  public playIntoAction() {
    this.isAttackCd = true
    this.node.alpha = 0
    new Tween(this.node)
      .to(0.5, { alpha: 1 })
      .call(() => {
        this.isAttackCd = false
      })
      .start()
  }
}
